#include "thread.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#include <unistd.h>

static int val_case1;
static int
func1(void *arg)
{
    int *p = arg;
    val_case1 += *p;
    printf("func1: %d\n", *p);
    return 0;
}


static void
test_case1()
{
    int val = 0;
    for (int i = 1; i <= 5; i++) {
        Thread_new(func1, &i, (int)sizeof(i));
        val += i;
    }
    printf("case1 begin join\n");
    Thread_join(NULL);
    assert(val == val_case1);
}

static int val_case2;
static int
func2(void *arg)
{
    int *p = arg;
    int val = *p * 100;
    val_case2 += val;
    printf("func2: %d\n", val);
    return val;
}

static void
test_case2()
{
    Thread_T arr[2];
    for (int i = 1; i <= 2; i++)
        arr[i-1] = Thread_new(func2, &i, (int)sizeof(i));

    printf("case2 begin join\n");
    int val = Thread_join(arr[1]);
    assert(val == 200);
    assert(val_case2 == 300); // For non-preempt arr[0] already done, run before arr[1]
}

static int val_case3;
static int
func3(void *arg)
{
    (void)arg;
    printf("func3 enter: %d\n", val_case3);
    val_case3 = 200;
    Thread_pause();
    val_case3 += 10;
    Thread_pause(); // Continue execute, because of only one thread
    return 0;
}

static void
test_case3()
{
    int val = 0;
    Thread_T t = Thread_new(func3, &val, (int)sizeof(val));

    val_case3 = 100;
    printf("case3 begin pause\n");
    Thread_pause();
    assert(val_case3 == 200);

    val_case3 = 50;
    printf("case3 begin join: %d\n", val_case3);
    Thread_join(t);
    assert(val_case3 == 60);
}

static int
func10(void *arg)
{
    const char *str = arg;
    for (;;) {
        printf("func10 sleep:%s ", str); fflush(stdout);
        usleep(5000*1000);
    }
    return 0;
}

static void
test_case10()
{
    Thread_new(func10, "a", 2);
    Thread_new(func10, "b", 2);
    printf("case10 begin join\n");
    Thread_join(NULL);
}

static void
test_non_preempt()
{
    Thread_init(0);
}

static void
test_preempt()
{
    Thread_init(1);
}

int main(int argc, char **argv)
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s [1,2,3]\n", argv[0]);
        return 0;
    }

    int c = argv[1][0];
    switch(c) {
        case '1':
            test_non_preempt();
            test_case1();
            break;
        case '2':
            test_non_preempt();
            test_case2();
            break;
        case '3':
            test_non_preempt();
            test_case3();
            break;
        case 'a':
            test_preempt();
            test_case10();
            break;
        default:
            fprintf(stderr, "Invalid case: %c\n", c);
    }

    Thread_exit(0);
    printf("main exit now!\n");
    return 0;
}

